<template>
  <el-form ref="formRef" :model="modelValue" :rules="rules">
    <el-row :gutter="16">
      <el-col v-for="item in items" :key="item.key" :span="item?.span || 24">
        <el-form-item :label="item.label" :prop="item.key">
          <slot :name="item.key">
            <component
              :is="getComponent(item)"
              v-bind="getProps(item)"
              v-model="modelValue[item.key]"
            ></component>
          </slot>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>

<script setup lang="ts">
import type { FormInstance } from 'element-plus'
import { ElInput, ElInputNumber, ElSelect } from 'element-plus'
import { omit } from 'lodash'
/**
 * 1.循环渲染组件 映射 v-model数据绑定
 * 2.校验规则
 * 3.校验触发
 * 4.纠正props
 * 5.自定义组件type
 */
//==============================//
/**
 * 外部属性
 */
const props = defineProps(['formItems', 'rules'])
/**
 * 数据双向绑定
 */
const modelValue = defineModel<any>()

/**
 * 过滤hidden
 */
const items = computed(() =>
  props.formItems.filter((item: any) => !item.hidden)
)

/**
 *  组件映射
 */
const componentMap: Record<string, any> = {
  input: ElInput,
  number: ElInputNumber,
  select: ElSelect,
}
/**
 * 自定义组件映射
 */
function getComponent(item: any) {
  // 解构参数
  const { type } = item
  // type 是一个函数或者是一个对象
  if (type && typeof type !== 'string') {
    return type
  }
  // 返回映射对象
  return componentMap[type || 'input']
}

/**
 *  {
    label: '姓名',
    key: 'name',
    type: 'input',
    placeholder: '请输入姓名',
  },
 */

/**
 * 处理除了 label key type 其他对象都传过去props
 */
const rootProps = ['label', 'key', 'type', 'hidden', 'span']
function getProps(item: any) {
  // 如果props存在则使用当前props
  if (item.props) return item.props
  // 否则返回省略了 rootProps 的对象
  return omit(item, rootProps)
}
/**
 * formRef实例对象
 */
const formRef = useTemplateRef<FormInstance>('formRef')
/**
 * 暴露校验方法
 */
defineExpose({
  validate(...args: any[]) {
    return formRef.value?.validate(...args)
  },
})
</script>
